from scipy import *
from numpy import power
from simu_common import Cbid, getPt, getRevenue, getStepRevenue

g_arrival_rate = 5
g_threshold_r = 0.0
g_threshold_t = Cbid(0.0, 0.0)

rng_poisson = stats.poisson(g_arrival_rate)
rng_p = stats.uniform()
rng_s = stats.uniform()

def bids_key(bid):
    return bid.r
  
def getThreshold(bids, l):
    '''
        assuming that the bids are sorted in order by p*s
        take the lth highest as threshold
    '''
    length = len(bids)
    if l < length:
        return bids[l].r
    else:
        return 0.0;
        
def getTopThreshold(bids, l):
    '''
        return the lth highest bid in top slots if any,
        as threshold
    '''
    length = len(bids)
    if l < length:
        return bids[l]
    else:
        return Cbid(0.0, 0.0);
    
def isAcceptable(bid):
    return bid.r > g_threshold_r

def isTopAcceptable(bid):
    return ((bid.p > g_threshold_t.p) and (bid.s > g_threshold_t.s))

def isTopAcceptable2(bid):
    return (bid.r > g_threshold_t.r)    
    
def getSingleStepNum():
    '''
        get the arrival number for one step
        with random generator Poisson
    '''
    return rng_poisson.rvs()
    
def getPS():
    '''
        get one pair of iid P and iid S with 
        random generator Uniform(0,1)
    '''
    return rng_p.rvs(), rng_s.rvs()

def refresh_rngs():
    '''
        refresh the random generators
    '''
    global rng_poisson
    global rng_p
    global rng_s
    del rng_poisson
    del rng_p
    del rng_s
    rng_poisson = stats.poisson(g_arrival_rate)
    rng_p = stats.uniform()
    rng_s = stats.uniform()

def refresh_thresholds(bids, tops, k, l):
    global g_threshold_t
    global g_threshold_r
    g_threshold_r = getThreshold(bids, k-1)
    g_threshold_t = getTopThreshold(tops, l)

def handle_tops(bids, tops, t, l, isTopAcceptable=isTopAcceptable):
    '''
        assuming the bids are sorted, lift qualified to top slots
    '''
    length = len(bids)
    bids_modified = False
    tops_modified = False
    tc = []
    if length > 0:
        for i in xrange(0, length):
            bid = bids[i]
            if isTopAcceptable(bid):
                tc.append(i)
                bids_modified = True
                
        offset = 0
        for i in tc:
            tops.append(bids.pop(i-offset))
            offset = offset + 1
            tops_modified = True
            
        if tops_modified:    
            tops.sort(key=bids_key, reverse=True)
            tops_modified = False
            
        overflow = len(tops) - t
        if overflow > 0:
            for i in xrange(0, overflow):
                bids.append(tops.pop())
                tops_modified = True
                bids_modified = True
                     
        if bids_modified:
            bids.sort(key=bids_key, reverse=True)
        
        if tops_modified:
            tops.sort(key=bids_key, reverse=True)
                

def exp_Rrate1(k=8, t=3, T=50, l=0, tao=1.4):
    '''
        k: capacity of the right side slots
        t: capacity of the top slots
        T: time horizon [0, T)
        l: the lth highest bid as threshold
        tao: the sorted position decaying factor
        return: the expected revenue rate
    '''
    refresh_rngs()
    bids = []
    tops = []
    bids2 = []
    tops2 = []
    tr = 0.0
    tr2 = 0.0
    
    for i in xrange(0, T):
        arrival = getSingleStepNum()        
        for j in xrange(0, arrival):
            p, s = getPS()
            bid = Cbid(p, s)
            if isAcceptable(bid):
                bids.append(bid)
                bids2.append(bid)
                        
        bids.sort(key=bids_key, reverse=True)    
        bids2.sort(key=bids_key, reverse=True)
        
        handle_tops(bids, tops, t, l)
        handle_tops(bids2, tops2, t, l, isTopAcceptable=isTopAcceptable2)
                        
        refresh_thresholds(bids, tops, k, l)
        
        tr = tr + getStepRevenue(bids, k, tao) + getStepRevenue(tops, t, tao)
        tr2 = tr2 + getStepRevenue(bids2, k, tao) + getStepRevenue(tops2, t, tao)
        
    return tr/T, tr2/T
    
def sample1(k=8, t=3):
    for i in xrange(0, t):
        r = 0.0
        r2 = 0.0
        it = 100
        for j in xrange(0, it):
            tr1, tr2 = exp_Rrate1(k=k, t=t, l=i)
            r = r + tr1
            r2 = r2 + tr2
        print i, r/it, r2/it 

if __name__ == "__main__":
    sample1()            
